feat(next): integrate Intercom provider lifecycle in app layout#2162
feat(next): integrate Intercom provider lifecycle in app layout#2162
Conversation
…ve boot options, and logout shutdown
bdb3437 to
5d05bad
Compare
There was a problem hiding this comment.
Pull request overview
This PR introduces an Intercom integration for the SvelteKit “(app)” shell so support chat can be launched from within the new ClientApp UI, and normalizes a few Tailwind sizing utilities in usage pages.
Changes:
- Add an Intercom provider/initializer wrapper in the authenticated app layout and expose an
openChatcallback to downstream UI. - Add an Intercom feature module (
$features/intercom) to build boot options and expose the Intercom context. - Replace a few arbitrary Tailwind sizes (
h-[200px],h-[250px],min-w-[230px]) with equivalent spacing-based classes.
Reviewed changes
Copilot reviewed 10 out of 11 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Exceptionless.Web/ClientApp/src/routes/(app)/project/[projectId]/usage/+page.svelte | Normalize skeleton/chart/tooltip sizing classes. |
| src/Exceptionless.Web/ClientApp/src/routes/(app)/project/[projectId]/configure/+page.svelte | Wire “contact support” action to Intercom context when available. |
| src/Exceptionless.Web/ClientApp/src/routes/(app)/organization/[organizationId]/usage/+page.svelte | Normalize skeleton/chart/tooltip sizing classes. |
| src/Exceptionless.Web/ClientApp/src/routes/(app)/+layout.svelte | Add IntercomProvider + initializer and pass openChat into the app shell/notifications. |
| src/Exceptionless.Web/ClientApp/src/lib/features/intercom/keys.ts | Define a shared context key for Intercom. |
| src/Exceptionless.Web/ClientApp/src/lib/features/intercom/intercom-initializer.svelte | New wrapper component to manage Intercom update cadence, routing updates, and shutdown on logout. |
| src/Exceptionless.Web/ClientApp/src/lib/features/intercom/index.ts | Public exports for the intercom feature module. |
| src/Exceptionless.Web/ClientApp/src/lib/features/intercom/context.svelte.ts | Add getIntercom() and a helper to build boot options from current user/org. |
| src/Exceptionless.Web/ClientApp/src/lib/features/auth/api.svelte.ts | Remove an extraneous stray diff artifact line. |
| src/Exceptionless.Web/ClientApp/package.json | Add svelte-intercom dependency. |
| src/Exceptionless.Web/ClientApp/package-lock.json | Lockfile updates for svelte-intercom and transitive dependency version bumps. |
Files not reviewed (1)
- src/Exceptionless.Web/ClientApp/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/Exceptionless.Web/ClientApp/src/lib/features/intercom/context.svelte.ts
Outdated
Show resolved
Hide resolved
src/Exceptionless.Web/ClientApp/src/lib/features/intercom/context.svelte.ts
Show resolved
Hide resolved
…ippet - Consolidate redundant intercom.update() calls into single effect tracking route and visibility - Extract getIntercom() into separate snippet to avoid context scoping issues - Both changes prevent duplicate updates and ensure context is properly available
Root cause: the sidebar support action was opening a fresh composer instead of the existing message history, and the new auth test needed immediate consistency so the seeded user was visible before login. The current staged set also carries the Intercom boot/auth wiring that this branch has been validating.
e4683c6 to
38f6705
Compare
There was a problem hiding this comment.
Pull request overview
This PR adds an Intercom integration to the /next authenticated SvelteKit app shell by introducing a dedicated Intercom feature slice, wiring provider/initializer lifecycle into the (app) layout, and adding a backend endpoint to mint Intercom JWTs for the current user.
Changes:
- Add
/api/v2/auth/intercomendpoint to return an Intercom JWT for the authenticated user, plus integration tests. - Introduce a new
$features/intercomslice (boot option builder, context key/getter, initializer component) and integrate it into the(app)layout with unread count support. - Add
svelte-intercomdependency and thread “open chat” behavior into UI entry points.
Reviewed changes
Copilot reviewed 16 out of 17 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Exceptionless.Tests/Controllers/AuthControllerTests.cs | Adds integration tests for the new auth/intercom endpoint. |
| src/Exceptionless.Web/Exceptionless.Web.csproj | Adds System.IdentityModel.Tokens.Jwt package for server-side JWT creation. |
| src/Exceptionless.Web/Controllers/AuthController.cs | Adds GET auth/intercom endpoint that issues an Intercom JWT for CurrentUser. |
| src/Exceptionless.Web/ClientApp/src/routes/(app)/project/[projectId]/usage/+page.svelte | Updates Tailwind sizing utilities for skeleton/chart/tooltip. |
| src/Exceptionless.Web/ClientApp/src/routes/(app)/project/[projectId]/configure/+page.svelte | Wires “contact support” to Intercom context showMessages(). |
| src/Exceptionless.Web/ClientApp/src/routes/(app)/organization/[organizationId]/usage/+page.svelte | Updates Tailwind sizing utilities for skeleton/chart/tooltip. |
| src/Exceptionless.Web/ClientApp/src/routes/(app)/+layout.svelte | Adds Intercom provider + initializer lifecycle integration and unread count plumbing. |
| src/Exceptionless.Web/ClientApp/src/routes/(app)/(components)/layouts/sidebar-user.svelte | Adds chat entry points + unread badge in the user/sidebar menu. |
| src/Exceptionless.Web/ClientApp/src/lib/features/intercom/keys.ts | Defines the Intercom context key. |
| src/Exceptionless.Web/ClientApp/src/lib/features/intercom/intercom-initializer.svelte | Adds Intercom update interval, route-sync updates, and logout shutdown behavior. |
| src/Exceptionless.Web/ClientApp/src/lib/features/intercom/index.ts | Exposes Intercom feature exports for layout/pages. |
| src/Exceptionless.Web/ClientApp/src/lib/features/intercom/context.svelte.ts | Implements boot option builder and getIntercom() context accessor. |
| src/Exceptionless.Web/ClientApp/src/lib/features/intercom/context.svelte.test.ts | Adds unit tests for Intercom boot option mapping. |
| src/Exceptionless.Web/ClientApp/src/lib/features/auth/index.svelte.ts | Re-exports getIntercomTokenQuery. |
| src/Exceptionless.Web/ClientApp/src/lib/features/auth/api.svelte.ts | Adds getIntercomTokenQuery() that calls auth/intercom. |
| src/Exceptionless.Web/ClientApp/package.json | Adds svelte-intercom dependency. |
| src/Exceptionless.Web/ClientApp/package-lock.json | Updates lockfile for svelte-intercom and other transitive dependency changes. |
Files not reviewed (1)
- src/Exceptionless.Web/ClientApp/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/Exceptionless.Web/ClientApp/src/routes/(app)/project/[projectId]/configure/+page.svelte
Show resolved
Hide resolved
src/Exceptionless.Web/ClientApp/src/lib/features/intercom/intercom-initializer.svelte
Outdated
Show resolved
Hide resolved
- Adds JWT expiration (1 hour) and issued-at claims to the Intercom token on the backend. - Configures the frontend query to automatically refresh the token every 55 minutes to ensure continuous authentication. - Centralizes help and documentation links and provides a fallback to GitHub issues when the Intercom messenger is unavailable or disabled.
There was a problem hiding this comment.
Pull request overview
This PR integrates Intercom into the authenticated SvelteKit app shell so the messenger boots/updates/shuts down based on real user/org state, backed by a new API endpoint that issues an Intercom user JWT.
Changes:
- Added
GET /api/v2/auth/intercomto mint a signed Intercom user JWT for the current authenticated user, plus integration tests. - Introduced a dedicated ClientApp Intercom feature slice (boot option builder, initializer/provider context, chat helper) and wired it into the
(app)layout lifecycle (including unread count wiring). - Centralized “Help” links into a shared module and updated a few UI sizing classes.
Reviewed changes
Copilot reviewed 23 out of 24 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Exceptionless.Tests/Controllers/AuthControllerTests.cs | Adds integration tests for the new /auth/intercom token endpoint. |
| src/Exceptionless.Web/Exceptionless.Web.csproj | Adds JWT package dependency needed for Intercom token minting. |
| src/Exceptionless.Web/Controllers/AuthController.cs | Adds GET auth/intercom to return a signed Intercom JWT for the current user. |
| src/Exceptionless.Web/ClientApp/src/routes/(app)/routes.svelte.ts | Uses centralized help-link constants instead of hardcoded URLs. |
| src/Exceptionless.Web/ClientApp/src/routes/(app)/project/[projectId]/usage/+page.svelte | Updates chart/skeleton sizing utility classes. |
| src/Exceptionless.Web/ClientApp/src/routes/(app)/project/[projectId]/configure/+page.svelte | Hooks “contact support” to Intercom/open-support fallback. |
| src/Exceptionless.Web/ClientApp/src/routes/(app)/organization/[organizationId]/usage/+page.svelte | Updates chart/skeleton sizing utility classes. |
| src/Exceptionless.Web/ClientApp/src/routes/(app)/+layout.svelte | Adds IntercomProvider + initializer and wires auth/org context + unread count into the app shell. |
| src/Exceptionless.Web/ClientApp/src/routes/(app)/(components)/layouts/sidebar-user.svelte | Adds chat entrypoint + unread badge and uses centralized help links. |
| src/Exceptionless.Web/ClientApp/src/lib/features/shared/help-links.ts | New shared constants for documentation/support/repo/API reference URLs. |
| src/Exceptionless.Web/ClientApp/src/lib/features/intercom/keys.ts | Defines the Intercom context key. |
| src/Exceptionless.Web/ClientApp/src/lib/features/intercom/intercom-initializer.svelte | Manages Intercom update cadence, route updates, and logout shutdown. |
| src/Exceptionless.Web/ClientApp/src/lib/features/intercom/index.ts | Barrel exports for the Intercom feature slice. |
| src/Exceptionless.Web/ClientApp/src/lib/features/intercom/context.svelte.ts | Builds Intercom boot options and exposes getIntercom() context accessor. |
| src/Exceptionless.Web/ClientApp/src/lib/features/intercom/context.svelte.test.ts | Unit tests for boot option mapping. |
| src/Exceptionless.Web/ClientApp/src/lib/features/intercom/config.ts | Defines token refresh cadence constants. |
| src/Exceptionless.Web/ClientApp/src/lib/features/intercom/config.test.ts | Unit tests for refresh cadence constants. |
| src/Exceptionless.Web/ClientApp/src/lib/features/intercom/chat.ts | Adds openSupportChat helper with Intercom + fallback behavior. |
| src/Exceptionless.Web/ClientApp/src/lib/features/intercom/chat.test.ts | Unit tests for chat helper behavior. |
| src/Exceptionless.Web/ClientApp/src/lib/features/auth/index.svelte.ts | Re-exports getIntercomTokenQuery. |
| src/Exceptionless.Web/ClientApp/src/lib/features/auth/api.svelte.ts | Adds TanStack Query wrapper for fetching/refreshing the Intercom token. |
| src/Exceptionless.Web/ClientApp/package.json | Adds svelte-intercom dependency. |
| src/Exceptionless.Web/ClientApp/package-lock.json | Locks svelte-intercom and updates various transitive dependencies. |
| .claude/agents/triage.md | Updates internal triage workflow wording/instructions. |
Files not reviewed (1)
- src/Exceptionless.Web/ClientApp/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/Exceptionless.Web/ClientApp/src/routes/(app)/+layout.svelte
Outdated
Show resolved
Hide resolved
Root cause: the Intercom token query reused a static cache key across auth-session changes, and the new auth/intercom contract updates were missing their HTTP and OpenAPI baselines.
Root cause: the initial package-lock regeneration pulled in unrelated transitive resolver updates instead of only recording the new Intercom packages required by the feature.
There was a problem hiding this comment.
Pull request overview
This PR integrates Intercom into the authenticated “next” app shell by adding a backend endpoint for Intercom messenger JWTs and wiring an Intercom provider/initializer into the Svelte layout so Intercom boots/updates/shuts down with auth + navigation state.
Changes:
- Added
GET /api/v2/auth/intercomto mint an Intercom JWT for the current authenticated user, with OpenAPI + integration test coverage. - Introduced a dedicated ClientApp Intercom feature slice (boot option builder, context access, initializer lifecycle, chat helper) and integrated it into the
(app)layout + relevant pages. - Centralized external help/support links and added
svelte-intercomdependency.
Reviewed changes
Copilot reviewed 25 out of 26 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/http/auth.http | Updates auth HTTP examples; adds request for /auth/intercom. |
| tests/Exceptionless.Tests/Controllers/Data/openapi.json | Updates OpenAPI snapshot with /api/v2/auth/intercom. |
| tests/Exceptionless.Tests/Controllers/AuthControllerTests.cs | Adds integration tests for Intercom token success + disabled scenarios. |
| src/Exceptionless.Web/Exceptionless.Web.csproj | Adds System.IdentityModel.Tokens.Jwt dependency for token minting. |
| src/Exceptionless.Web/Controllers/AuthController.cs | Implements /auth/intercom endpoint that returns a signed JWT. |
| src/Exceptionless.Web/ClientApp/src/routes/(app)/routes.svelte.ts | Uses shared help-link constants for Help routes. |
| src/Exceptionless.Web/ClientApp/src/routes/(app)/project/[projectId]/usage/+page.svelte | Updates chart/skeleton sizing classes. |
| src/Exceptionless.Web/ClientApp/src/routes/(app)/project/[projectId]/configure/+page.svelte | Hooks “open chat” into Intercom context via feature helper. |
| src/Exceptionless.Web/ClientApp/src/routes/(app)/organization/[organizationId]/usage/+page.svelte | Updates chart/skeleton sizing classes. |
| src/Exceptionless.Web/ClientApp/src/routes/(app)/+layout.svelte | Adds IntercomProvider + IntercomInitializer and propagates chat/unread state into sidebar. |
| src/Exceptionless.Web/ClientApp/src/routes/(app)/(components)/layouts/sidebar-user.svelte | Adds chat entry + unread badge; switches help links to constants. |
| src/Exceptionless.Web/ClientApp/src/lib/features/shared/help-links.ts | New: central constants for documentation/support/GitHub/API links. |
| src/Exceptionless.Web/ClientApp/src/lib/features/intercom/* | New: Intercom context key, initializer lifecycle, boot options builder, config, chat helper, unit tests. |
| src/Exceptionless.Web/ClientApp/src/lib/features/auth/index.svelte.ts | Re-exports getIntercomTokenQuery. |
| src/Exceptionless.Web/ClientApp/src/lib/features/auth/api.svelte.ts | Adds getIntercomTokenQuery with refresh cadence. |
| src/Exceptionless.Web/ClientApp/package.json | Adds svelte-intercom. |
| src/Exceptionless.Web/ClientApp/package-lock.json | Locks svelte-intercom + @intercom/messenger-js-sdk. |
| .claude/agents/triage.md | Updates internal triage agent guidance text. |
Files not reviewed (1)
- src/Exceptionless.Web/ClientApp/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /// <summary> | ||
| /// Get the current user's Intercom messenger token. | ||
| /// </summary> | ||
| /// <response code="200">Intercom messenger token</response> | ||
| /// <response code="422">Intercom is not configured</response> | ||
| [HttpGet("intercom")] | ||
| public Task<ActionResult<TokenResult>> GetIntercomTokenAsync() | ||
| { | ||
| if (!_intercomOptions.EnableIntercom || String.IsNullOrWhiteSpace(_intercomOptions.IntercomSecret)) | ||
| { | ||
| ModelState.AddModelError("intercom", "Intercom is not enabled."); | ||
| return Task.FromResult<ActionResult<TokenResult>>(ValidationProblem(ModelState)); |
| {#if isAuthenticated} | ||
| {#if isChatEnabled} | ||
| <IntercomProvider | ||
| appId={intercomAppId} | ||
| autoboot={shouldBootIntercom} | ||
| bootOptions={intercomBootOptions} | ||
| onUnreadCountChange={onIntercomUnreadCountChange} | ||
| > | ||
| {@render intercomShell()} | ||
| </IntercomProvider> | ||
| {:else} | ||
| {@render appShell(openChatFallback)} | ||
| {/if} |
| <div class="space-y-4"> | ||
| <Skeleton class="h-12 w-3/4" /> | ||
| <Skeleton class="h-[200px] w-full" /> | ||
| <Skeleton class="h-50 w-full" /> |
| </div> | ||
|
|
||
| <Chart.Container config={chartConfig} class="aspect-auto h-[250px] w-full"> | ||
| <Chart.Container config={chartConfig} class="aspect-auto h-62.5 w-full"> |
| > | ||
| {#snippet tooltip()} | ||
| <Chart.Tooltip class="min-w-[230px]" indicator="line" labelFormatter={(v) => formatDateLabel(v as Date)} /> | ||
| <Chart.Tooltip class="min-w-57.5" indicator="line" labelFormatter={(v) => formatDateLabel(v as Date)} /> |
| <div class="space-y-4"> | ||
| <Skeleton class="h-12 w-3/4" /> | ||
| <Skeleton class="h-[200px] w-full" /> | ||
| <Skeleton class="h-50 w-full" /> |
| </div> | ||
|
|
||
| <Chart.Container config={chartConfig} class="aspect-auto h-[250px] w-full"> | ||
| <Chart.Container config={chartConfig} class="aspect-auto h-62.5 w-full"> |
| > | ||
| {#snippet tooltip()} | ||
| <Chart.Tooltip class="min-w-[230px]" indicator="line" labelFormatter={(v) => formatDateLabel(v as Date)} /> | ||
| <Chart.Tooltip class="min-w-57.5" indicator="line" labelFormatter={(v) => formatDateLabel(v as Date)} /> |
Summary
Root Cause (if bug fix)
What I Changed and Why
Tech Debt Assessment
Test Plan